/**
 * All the functions needed to render objects
 *
 * Originally written by: Jonas Strandstedt
 */

#define BUFFER_OFFSET(i) ((char *)NULL + (i))

/** 
 * initObjectArray reades an .obj file 
 * @param Vertex **varray = a pointer to the vertex array
 * @param int **iarray = a pointer to the index array
 * @param char filename[] = the filename of the .obj file
 * @param int *vsize = the size of the varray
 * @param int *isize = the size of the iarray
 * @param GLenum *rf = the renderformat variable, maybe not needed soon		<= Remove maybe?
 *
 * Reades the file twice, first time counts the number of rows for each array
 * and then allocates enough memory. At last it reads the file again and then
 * generates the right arrays.
 */
void initObjectArray(Vertex **varray, int **iarray, char filename[], int *vsize, int *isize, float scale, XYZ rotation) {
	// debugInit = 1 shows all debug information in the console output
	short debugInit = 0;
	
	// temporary 
	int vertexSize = 0;
	int vertexNormalSize = 0;
	int vertexTextureSize = 0;
	int indicesSize = 0;
	
	float f1,f2,f3,f4,f5,f6,f7,f8,f9;
	int i1,i2,i3,i4,i5,i6,i7,i8,i9;
	char line[150];
	float maxtex;
	
	FILE *fi;
	/*	START LINE COUNT */
	fi = fopen(filename, "r");
	if (fi==NULL) {
		printf("null object");
	}
	while (fgets(line,150,fi)!=NULL)
	{
		if (sscanf( line, "v %f%f%f", &f1, &f2, &f3)) {
			vertexSize+=3;
		}
		if (sscanf( line, "vn %f%f%f", &f1, &f2, &f3)) {
			vertexNormalSize+=3;
		}
		if (sscanf( line, "vt %f%f%f", &f1, &f2, &f3)) {
			vertexTextureSize+=3;
		}
		if (vertexTextureSize > 0) {
			if (sscanf( line, "f %i/%i/%i %i/%i/%i %i/%i/%i", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9)) {
				indicesSize+=3;
			}
		} else {
			if (sscanf( line, "f %i//%i %i//%i %i//%i", &i1, &i2, &i3, &i4, &i5, &i6)) {
				indicesSize+=3;
			}
		}
	}
	/*	END LINE COUNT */
	
	// allocate memory for all arrays
	(*isize) = indicesSize;
	(*vsize) = indicesSize;
	
	// float arrays
	float *tempVertexArray = (float*)malloc(vertexSize*sizeof(float));
	float *tempVertexNormalArray = (float*)malloc(vertexNormalSize*sizeof(float));
	float *tempVertexTextureArray = (float*)malloc(vertexTextureSize*sizeof(float));
	(*varray) = (Vertex*)malloc((*vsize)*sizeof(Vertex));
	
	// int arrays
	*iarray = (int*)malloc((*isize)*sizeof(int));
	int *tempNormalIndicesArray = (int*)malloc((*isize)*sizeof(int));
	int *tempTextureIndicesArray = (int*)malloc((*isize)*sizeof(int));
	
	// keeping track of the array indexes
	int i = 0;
	int n = 0;
	int m = 0;
	int w = 0;
	
	// Go back to beginning of file
	fseek(fi, 0, SEEK_SET);
	
	while (fgets(line,150,fi)!=NULL)
	{
		if (sscanf( line, "v %f%f%f", &f1, &f2, &f3)) {
			(tempVertexArray)[i] = f1;
			i++;
			(tempVertexArray)[i] = f2;
			i++;
			(tempVertexArray)[i] = f3;
			i++;
			if (debugInit == 1)
				printf("vertex: %f  %f  %f \n",(tempVertexArray)[i-3],(tempVertexArray)[i-2],(tempVertexArray)[i-1]);
		}
		if (sscanf( line, "vn %f%f%f", &f1, &f2, &f3)) {
			(tempVertexNormalArray)[n] = f1;
			n++;
			(tempVertexNormalArray)[n] = f2;
			n++;
			(tempVertexNormalArray)[n] = f3;
			n++;
			if (debugInit == 1)
				printf("vertexNormal: %f  %f  %f \n",(tempVertexNormalArray)[n-3],(tempVertexNormalArray)[n-2],(tempVertexNormalArray)[n-1]);
		}
		
		if (sscanf( line, "vt %f%f%f", &f1, &f2, &f3)) {
			(tempVertexTextureArray)[w] = f1;
			maxtex = ((tempVertexTextureArray)[w] > maxtex) ? (tempVertexTextureArray)[w] : maxtex;
			w++;
			(tempVertexTextureArray)[w] = f2;
			maxtex = ((tempVertexTextureArray)[w] > maxtex) ? (tempVertexTextureArray)[w] : maxtex;
			w++;
			(tempVertexTextureArray)[w] = f3;
			maxtex = ((tempVertexTextureArray)[w] > maxtex) ? (tempVertexTextureArray)[w] : maxtex;
			w++;
			if (debugInit == 1)
				printf("vertexTexture: %f  %f  %f \n",(tempVertexTextureArray)[w-3],(tempVertexTextureArray)[w-2],(tempVertexTextureArray)[w-1]);
		}
		
		if (vertexTextureSize > 0) {
			if (sscanf( line, "f %i/%i/%i %i/%i/%i %i/%i/%i", &i1, &i2, &i3, &i4, &i5, &i6, &i7, &i8, &i9)) {
				(*iarray)[m] = i1-1;
				(tempTextureIndicesArray)[m] = i2-1;
				(tempNormalIndicesArray)[m] = i3-1;
				m++;
				(*iarray)[m] = i4-1;
				(tempTextureIndicesArray)[m] = i5-1;
				(tempNormalIndicesArray)[m] = i6-1;
				m++;
				(*iarray)[m] = i7-1;
				(tempTextureIndicesArray)[m] = i8-1;
				(tempNormalIndicesArray)[m] = i9-1;
				m++;
				if (debugInit == 1)
					printf("vi: %i  %i  %i   vn: %i  %i  %i \n",(*iarray)[m-3],(*iarray)[m-2],(*iarray)[m-1],(tempNormalIndicesArray)[m-3],(tempNormalIndicesArray)[m-2],(tempNormalIndicesArray)[m-1]);
			}
		} else {
			if (sscanf( line, "f %i//%i %i//%i %i//%i", &i1, &i2, &i3, &i4, &i5, &i6)) {
				(*iarray)[m] = i1-1;
				(tempNormalIndicesArray)[m] = i2-1;
				m++;
				(*iarray)[m] = i3-1;
				(tempNormalIndicesArray)[m] = i4-1;
				m++;
				(*iarray)[m] = i5-1;
				(tempNormalIndicesArray)[m] = i6-1;
				m++;
				if (debugInit == 1)
					printf("vi: %i  %i  %i   vn: %i  %i  %i \n",(*iarray)[m-3],(*iarray)[m-2],(*iarray)[m-1],(tempNormalIndicesArray)[m-3],(tempNormalIndicesArray)[m-2],(tempNormalIndicesArray)[m-1]);
			}	
		}
	}
	fclose(fi);
	// end of file read
	
	// creating the vertex array
	i=0;n=0;m=0;
	int normalIndex = 0;
	int textureIndex = 0;
	int vertexIndex = 0;
	printf("Arraysize: %i, maxtex = %f",(*vsize), maxtex);
	while (m<(*vsize)) {
		if (debugInit == 1)
			printf("\nAdding vertex %i, startNormal:%i startVertex:%i\n",m,tempNormalIndicesArray[m]*3,(*iarray)[m]*3);
		
		normalIndex = tempNormalIndicesArray[m]*3;
		textureIndex = tempTextureIndicesArray[m]*3;
		vertexIndex = (*iarray)[m]*3;
		(*iarray)[m] = m;
		
		int q = 0;
		while (q < 3) {
			(*varray)[m].location[q] = tempVertexArray[vertexIndex+q]*scale;
			(*varray)[m].normal[q] = tempVertexNormalArray[normalIndex+q];
			(*varray)[m].colour[q] = 1.0;
			q++;
		}
		
		XYZ temp;
		XYZ normal_temp;
		temp.x = (*varray)[m].location[0];
		temp.y = (*varray)[m].location[1];
		temp.z = (*varray)[m].location[2];
		normal_temp.x = (*varray)[m].normal[0];
		normal_temp.y = (*varray)[m].normal[1];
		normal_temp.z = (*varray)[m].normal[2];
		
		// rotare around x
		(*varray)[m].location[0] = temp.x;
		(*varray)[m].location[1] = cos(rotation.x)*temp.y - sin(rotation.x)*temp.z;
		(*varray)[m].location[2] = sin(rotation.x)*temp.y + cos(rotation.x)*temp.z;
		
		temp.x = (*varray)[m].location[0];
		temp.y = (*varray)[m].location[1];
		temp.z = (*varray)[m].location[2];
		normal_temp.x = (*varray)[m].normal[0];
		normal_temp.y = (*varray)[m].normal[1];
		normal_temp.z = (*varray)[m].normal[2];
		// rotare around y
		(*varray)[m].location[0]= cos(rotation.y)*temp.x + sin(rotation.y)*temp.y;
		(*varray)[m].location[1] = temp.y;
		(*varray)[m].location[2] = -sin(rotation.y)*temp.x + cos(rotation.y)*temp.z;
		
		temp.x = (*varray)[m].location[0];
		temp.y = (*varray)[m].location[1];
		temp.z = (*varray)[m].location[2];
		// rotare around z
		(*varray)[m].location[0] = cos(rotation.z)*temp.x + sin(rotation.z)*temp.y;
		(*varray)[m].location[1] = -sin(rotation.z)*temp.x + cos(rotation.z)*temp.y;
		(*varray)[m].location[2] = temp.z;
		
		// rotare around x
		normal_temp.x = (*varray)[m].normal[0];
		normal_temp.y = (*varray)[m].normal[1];
		normal_temp.z = (*varray)[m].normal[2];
		(*varray)[m].normal[0] = normal_temp.x;
		(*varray)[m].normal[1] = cos(rotation.x)*normal_temp.z - sin(rotation.x)*normal_temp.y;
		(*varray)[m].normal[2] = sin(rotation.x)*normal_temp.z + cos(rotation.x)*normal_temp.y;
		// rotare around y
		normal_temp.x = (*varray)[m].normal[0];
		normal_temp.y = (*varray)[m].normal[1];
		normal_temp.z = (*varray)[m].normal[2];
		(*varray)[m].normal[0] = cos(rotation.y)*normal_temp.x + sin(rotation.y)*normal_temp.y;
		(*varray)[m].normal[1] = normal_temp.y;
		(*varray)[m].normal[2] = -sin(rotation.y)*normal_temp.x + cos(rotation.y)*normal_temp.y;
		// rotare around z
		normal_temp.x = (*varray)[m].normal[0];
		normal_temp.y = (*varray)[m].normal[1];
		normal_temp.z = (*varray)[m].normal[2];
		(*varray)[m].normal[0] = cos(rotation.z)*normal_temp.x + sin(rotation.z)*normal_temp.y;
		(*varray)[m].normal[1] = -sin(rotation.z)*normal_temp.x + cos(rotation.z)*normal_temp.y;
		(*varray)[m].normal[2] = normal_temp.z;
		
		if (debugInit == 1) {
			printf("normal added: %f %f %f \n",(*varray)[m].normal[0],(*varray)[m].normal[1],(*varray)[m].normal[2]);
			printf("vertex pos added: %f %f %f \n",(*varray)[m].location[0],(*varray)[m].location[1],(*varray)[m].location[2]);
		}
		(*varray)[m].colour[3] = 1.0;
		
		if (vertexTextureSize > 0) {
			(*varray)[m].tex[0] = tempVertexTextureArray[textureIndex];
			(*varray)[m].tex[1] = tempVertexTextureArray[textureIndex+1];
			//(*varray)[m].tex[0] = tempVertexNormalArray[textureIndex];
			//(*varray)[m].tex[1] = tempVertexNormalArray[textureIndex+1];
		} else {
			(*varray)[m].tex[0] = 1.0;
			(*varray)[m].tex[1] = 1.0;
		}
		m++;
	}
	printf("... Array initiated!\n");
	// free up memory
	free(tempVertexArray);
	free(tempVertexNormalArray);
	free(tempNormalIndicesArray);
	free(tempVertexTextureArray);
	free(tempTextureIndicesArray);
}

/**
 * addMeshTexture adds specified texture to an object
 * @param PlayerObject *obj = the object to be rendered
 * @param char texture[100] = the filename of the texture
 *
 * Right now it loads a new texture each time which is silly, make a function that
 * don't load dublicate texures!
 */
void addMeshTexture(ObjectMesh *obj, char texture[100]) {
	glEnable(GL_TEXTURE_2D); // Enable texturing
    glGenTextures(1, &obj->texture); // Generate 2 unique texture IDs to use
    glBindTexture(GL_TEXTURE_2D, obj->texture); // Activate first texture
    // This peculiar file path is for an MacOS X application bundle

    glfwLoadTexture2D(texture, GLFW_BUILD_MIPMAPS_BIT); // Load image
    glBindTexture(GL_TEXTURE_2D, 0); // Deactivate the texture again
}

/**
 * drawBullet
 */
void drawBullet(Bullet *theBullet) {
	
	if (theBullet->texture != -1) {
		glBindTexture(GL_TEXTURE_2D, textureArray[theBullet->texture]); 
	}
	glPushMatrix();
	glTranslatef((*theBullet).pos.x, (*theBullet).pos.y, (*theBullet).pos.z);
	glRotatef((*theBullet).angle.x * 360 / M_PI / 2, 1.0f, 0, 0);
	glRotatef((*theBullet).angle.y * 360 / M_PI / 2, 0, 1.0f, 0);
	glRotatef((*theBullet).angle.z * 360 / M_PI / 2, 0, 0, 1.0f);
	drawMeshVBO(modelArray[(*theBullet).model]);
	glPopMatrix();
	
	if (theBullet->texture != -1) {
		glBindTexture(GL_TEXTURE_2D, 0); 
	}
}

/**
 * drawCollisionObject
 */
void drawCollisionObject(CollisionObject *obj) {
	if (obj->texture != -1) {
		glBindTexture(GL_TEXTURE_2D, textureArray[obj->texture]); 
	}
	glPushMatrix();
	glTranslatef((*obj).pos.x, (*obj).pos.y, (*obj).pos.z);
	glRotatef((*obj).angle.x * 360 / M_PI / 2, 1.0f, 0, 0);
	glRotatef((*obj).angle.y * 360 / M_PI / 2, 0, 1.0f, 0);
	glRotatef((*obj).angle.z * 360 / M_PI / 2, 0, 0, 1.0f);
	drawMeshVBO(modelArray[(*obj).model]);
	glPopMatrix();
	if (obj->texture != -1) {
		glBindTexture(GL_TEXTURE_2D, 0); 
	}
}

/**
 * initObjectMesh allocates memory for the parts of the object
 * @param ObjectMesh *obj = the objects mesh to be initiated
 * @param char filename[] = the filename of the objects file to be loaded
 */
void initObjectMesh(ObjectMesh *obj, char filename[100], float scale, XYZ rotation) {
	
	printf("Initialize mesh: %s\n",filename);
	
	// setting the IDs to 0 so it is possible to know later in case something goes wrong
	obj->vBufferID = 0;
	obj->iBufferID = 0;
	obj->vArraySize = 0;
	obj->iArraySize = 0;
	
	obj->texture = 0;
	
	initObjectArray(&(*obj).varray, &(*obj).iarray, filename, &(*obj).vArraySize, &(*obj).iArraySize, scale, rotation);
	
	glGenBuffers(1, &(*obj).vBufferID);
    glBindBuffer(GL_ARRAY_BUFFER, (*obj).vBufferID);
    glBufferData(GL_ARRAY_BUFFER, (*obj).vArraySize*sizeof(Vertex), (*obj).varray, GL_STATIC_DRAW);
	
	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
	glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
	glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
	glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
	
    glGenBuffers(1, &(*obj).iBufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, (*obj).iBufferID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, (*obj).iArraySize*sizeof(int), (*obj).iarray, GL_STATIC_DRAW);
	
	// in case of error, print it
    GLuint errorID = glGetError();
    if(errorID != GL_NO_ERROR) {
        printf("OpenGL error: %s\n", gluErrorString(errorID));
        printf("Attempting to proceed anyway. Expect rendering errors or a crash.\n");
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	
	objectRadius(obj);
	maxmin(obj);
	
	//char message[50];
	//sprintf(message,"Done initializing mesh: %s",filename);
	//textMessageAdd(message);
}

/** 
 * drawStaticObject
 * @param StaticObject *obj = The staticObject that should be drawn
 */
void drawStaticObject(StaticObject *obj) {
	glPushMatrix();
	
	glTranslatef((*obj).pos.x, (*obj).pos.y, (*obj).pos.z);
	glRotatef((*obj).angle.x * 360 / M_PI / 2, 1.0f, 0, 0);
	glRotatef((*obj).angle.y * 360 / M_PI / 2, 0, 1.0f, 0);
	glRotatef((*obj).angle.z * 360 / M_PI / 2, 0, 0, 1.0f);
	drawMeshVBO((*obj).mesh);
	
	glPopMatrix();
}

/**
 * drawObjectTriangles draws the object using direct rendering
 * @param PlayerObject *obj = the object to be rendered
 *
 * This is a slow method rendering flat-shaded objects
 */
void drawObjectDirectRendering(PlayerObject *obj) {
	if (obj->mesh->texture != 0) {
		glBindTexture(GL_TEXTURE_2D, obj->mesh->texture); 
	}

	glBegin(GL_TRIANGLES);
	int i=0;
	while (i<obj->mesh->iArraySize) {
		Vertex tmp = obj->mesh->varray[i];
		
		//use this if you want to debug
		/*
		if (true) {
			printf("\n\n==== New Vertex (%i)====\n",i);
			printf("glNormal3f(%f,%f,%f)\n",tmp.normal[0],tmp.normal[1],tmp.normal[2]);
			printf("glVertex3f(%f,%f,%f)\n",tmp.location[0],tmp.location[1],tmp.location[2]);
		}
		 */
		
		glNormal3f(tmp.normal[0],tmp.normal[1],tmp.normal[2]);
		glColor4f(tmp.colour[0],tmp.colour[1],tmp.colour[2],tmp.colour[3]);
		glTexCoord2d(tmp.tex[0],tmp.tex[1]);
		glVertex3f(tmp.location[0],tmp.location[1],tmp.location[2]);
		i++;
	}
	glEnd();

	if (obj->mesh->texture != 0) {
		glBindTexture(GL_TEXTURE_2D, 0); 
	}
}

/**
 * drawObjectVBO draws the object using Vertex Buffer Object
 * @param PlayerObject *obj = the object to be rendered
 *
 * This method is faster than direct rendering
 */
void drawMeshVBO(ObjectMesh *obj) {
	if (obj->texture != 0) {
		glBindTexture(GL_TEXTURE_2D, obj->texture); 
	}
	
	glBindBuffer(GL_ARRAY_BUFFER, obj->vBufferID);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, obj->iBufferID);
	//glInterleavedArrays(GL_T2F_C4F_N3F_V3F, 16*sizeof(GLubyte*), (GLubyte*)NULL);
	//glInterleavedArrays(GL_T2F_C4F_N3F_V3F, 16*sizeof(GLubyte*), (GLubyte*)NULL);
	
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	glEnableClientState(GL_COLOR_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_VERTEX_ARRAY);
	
	// Resetup our pointers.  This doesn't reinitialise any data, only how we walk through it
	glTexCoordPointer(2, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12));
	glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(20));
	glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(32));
	glVertexPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(0));
	
	glDrawElements(GL_TRIANGLES, obj->iArraySize, GL_UNSIGNED_INT, BUFFER_OFFSET(0));
	
	glDisableClientState(GL_TEXTURE_COORD_ARRAY);
	glDisableClientState(GL_COLOR_ARRAY);
	glDisableClientState(GL_NORMAL_ARRAY);
	glDisableClientState(GL_VERTEX_ARRAY);
	
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
	
	if (obj->texture != 0) {
		glBindTexture(GL_TEXTURE_2D, 0); 
	}
}

/**
 * drawPlayerVBO draws the players mesh and parts meshes
 * @param PlayerObject *obj = the player to be rendered
 */
void drawPlayerVBO(PlayerObject *obj) {
	drawMeshVBO(obj->mesh);
	int n = 0;
	while (n < (*obj).partsUsed) {
		glPushMatrix();
		StaticObject *temp = (obj->parts + n);
		glTranslatef((*temp).pos.x, (*temp).pos.y, (*temp).pos.z);
		glRotatef((*temp).angle.z * 360 / M_PI / 2, 0, 0, 1.0f);
		drawMeshVBO(temp->mesh);
		glPopMatrix();
		n++;
	}
}

/**
 * drawObject is a function determing what rendering methos to use
 * @param PlayerObject *obj = the object to be rendered
 */
void drawPlayer(PlayerObject *obj) {
	if (obj->isDead == 0) {
		glPushMatrix();
		
		glTranslatef((*obj).pos.x, (*obj).pos.y, (*obj).pos.z);
		glRotatef((*obj).angle.x * 360 / M_PI / 2, 1.0f, 0, 0);
		glRotatef((*obj).angle.y * 360 / M_PI / 2, 0, 1.0f, 0);
		glRotatef((*obj).angle.z * 360 / M_PI / 2, 0, 0, 1.0f);
		
		// effect handler
		if ((*obj).effect != 0) {
			switch ((*obj).effect) {
					// explosion
				case PLAYER_EFFECT_EXPLODE:
					if ((*obj).effect_timer < 1.0) {
						drawObjectExploding(obj,(*obj).effect_timer,5.0);
					} else {
						obj->isDead = 1;
					}
					(*obj).effect_timer += 0.03;
					break;
					
					// sinking
				case PLAYER_EFFECT_SINK:
					if ((*obj).effect_timer < 1.0) {
						drawObjectSinking(obj,(*obj).effect_timer);
					} else {
						obj->isDead = 1;
					}
					(*obj).effect_timer += 0.003;
					break;
					
					// whirl pool
				case PLAYER_EFFECT_WHIRL_POOL:
					if ((*obj).effect_timer < 1.0) {
						drawObjectWhirlpool(obj,(*obj).effect_timer, 10, 1);
					} else {
						obj->isDead = 1;
					}
					(*obj).effect_timer += 0.005;
					break;
				default:
					// no effect
					drawPlayerVBO(obj);
					break;
			}
		} else {
			drawPlayerVBO(obj);
		}
		glPopMatrix();
	} else {
		if (obj->isDead < PLAYER_RESPAWN_TIME) {
			obj->isDead++;
		}else {
			obj->isDead = 0;
			spawnPlayer(obj);
		}
	}

}

/**
 * objectRadius calculates the radius of the object, used for boundingSphere
 * @param ObjectMesh *obj = the mesh of the object.
 */
void objectRadius(ObjectMesh *obj){
	int i;
	float radius;
	for (i = 0; i < obj->vArraySize; i++) {
		radius += sqrt((obj->varray[i].location[0])*(obj->varray[i].location[0])+(obj->varray[i].location[1])*(obj->varray[i].location[1])+(obj->varray[i].location[2])*(obj->varray[i].location[2]));
	}
	(*obj).radius = radius / obj->vArraySize;
	printf("Radius = %.3f\n",(*obj).radius);
}

/**
 * maxmin finds out the maximum and minimum values of the vertices XYZ positions, used to create hitbox.
 * @param ObjectMesh *obj = the mesh of the object.
 */
void maxmin(ObjectMesh *obj){
	int i;
	XYZ tempmax, tempmin;
	tempmax.x = obj->varray[0].location[0]; tempmin.x = obj->varray[0].location[0];
	tempmax.y = obj->varray[0].location[1]; tempmin.y = obj->varray[0].location[1];
	tempmax.z = obj->varray[0].location[2]; tempmin.z = obj->varray[0].location[2];
	for (i = 0; i < obj->vArraySize; i++) {
		if(obj->varray[i].location[0] > tempmax.x){
			tempmax.x = obj->varray[i].location[0];
		}
		else if(obj->varray[i].location[0] < tempmin.x){
			tempmin.x = obj->varray[i].location[0];
		}
		if (obj->varray[i].location[1] > tempmax.y) {
			tempmax.y = obj->varray[i].location[1];
		}
		else if(obj->varray[i].location[1] < tempmin.y){
			tempmin.y = obj->varray[i].location[1];
		}
		if(obj->varray[i].location[2] > tempmax.z){
			tempmax.z = obj->varray[i].location[2];
		}
		else if(obj->varray[i].location[2] < tempmin.z){
			tempmin.z = obj->varray[i].location[2];
		}
	}
	obj->max.x = tempmax.x; obj->min.x = tempmin.x;
	obj->max.y = tempmax.y; obj->min.y = tempmin.y;
	obj->max.z = tempmax.z; obj->min.z = tempmin.z;
	
	obj->meshCenter.x = (obj->max.x + obj->min.x)/2;
	obj->meshCenter.y = (obj->max.y + obj->min.y)/2;
	obj->meshCenter.z = (obj->max.z + obj->min.z)/2;
}